import { Disposable, StatusBarAlignment, StatusBarItem, ThemeColor, window } from "vscode";
import * as express from "express";
import * as expressWs from "express-ws";
import { Server } from "http";
import { CloseEvent, MessageEvent, WebSocket } from "ws";
import { ERRORS, isError } from "../common/Errors";
import { exec } from "child_process";
import { Express } from "express";

/**
 * WebSocket 状态
 */
class WebSocketStatus {

    constructor(
        public msg: string = "浏览器插件未连接，点击连接",
        public connected: boolean = false
    ) {
    }
}

/**
 * 和浏览器端通讯的 WebSocket 服务
 */
class WebSocketService implements Disposable {

    private readonly port = 41314;
    /**
     * Express App
     */
    private app: Express;
    /**
     * WebSocket 服务端
     */
    private server?: Server;

    /**
     * WebSocket 浏览器插件连接
     */
    private client?: WebSocket;

    /**
     * 状态条 Item
     */
    private statusBarItem: StatusBarItem;

    constructor() {
        this.statusBarItem = window.createStatusBarItem(StatusBarAlignment.Left, 0);
        this.updateStatusBarItem(new WebSocketStatus());
        this.statusBarItem.text = "LeetCode Ultimate";

        this.app = express();
    }

    /**
     * 启动服务
     */
    start() {
        this.statusBarItem.show();

        // 允许跨域请求
        this.app.all("*", function (_req, res, next) {
            res.header("Access-Control-Allow-Origin", "*");
            res.header("Access-Control-Allow-Methods", "*");
            res.header("Access-Control-Allow-Headers", "*");
            next();
        });

        // 处理 WebSocket 连接
        expressWs(this.app).app.ws("/", (ws) => {
            this.onOpen(ws);
        });

        this.server = this.app.listen(this.port);
        console.log("WebSocket 服务启动完成");

        this.openBrowser();
    }

    /**
     * 销毁服务
     */
    dispose(): any {
        this.server?.close();
        this.statusBarItem.hide();
        console.log("WebSocket 服务停止");
    }

    /**
     * 检查是否连接
     */
    isConnected(): boolean {
        return !!this.client;
    }

    /**
     * 浏览器插件连接
     */
    private onOpen(ws: WebSocket) {
        console.log("浏览器插件连接成功");
        this.updateStatusBarItem(new WebSocketStatus("浏览器插件连接成功", true));
        this.client?.close(); // 新连接到时关闭旧连接
        this.client = ws;
        ws.onmessage = (ev) => this.onMessage(ev);
        ws.onclose = (ev) => this.onClose(ev);
    }

    private _currentKey: number = 1;
    private _callbacks: Record<number, (data: any) => void> = {};

    /**
     * 向浏览器插件发送信息，并等待返回
     */
    async send<T>(message: any, timeout: number = 3000): Promise<T> {
        if (!this.client) {
            // 没有浏览器插件连接返回错误
            return Promise.reject(ERRORS.browserNotConnection);
        }
        return new Promise((resolve, reject) => {
            const key = this._currentKey++;
            message.key = key;
            let cancel = false;

            // 取消等待直接返回错误
            const _cancel = (error: any) => {
                cancel = true;
                delete this._callbacks[key];
                reject(error);
            };
            // 超时取消等待
            const timeoutCancel = setTimeout(() => {
                _cancel(ERRORS.requestTimeout);
            }, timeout);

            // 等待回调
            this._callbacks[key] = (data) => {
                clearTimeout(timeoutCancel);
                if (!cancel) {
                    if (isError(data.result)) {
                        reject(data.result);
                    } else {
                        resolve(data.result);
                    }
                    delete this._callbacks[key];
                }
            };

            // 发送信息
            this.client?.send(JSON.stringify(message));
        });
    }

    /**
     * 处理浏览器插件的信息
     */
    private onMessage(event: MessageEvent) {
        if (typeof event.data !== "string") {
            return console.log(ERRORS.notSupportData, event);
        }
        const result = JSON.parse(event.data);
        if (result.key) {
            this._callbacks[result.key]?.(result);
        }
    }


    /**
     * 处理关闭事件
     */
    private onClose(_ev: CloseEvent) {
        this.client = undefined;
        this.updateStatusBarItem(new WebSocketStatus());
    }

    /**
     * 更新状态条
     */
    private updateStatusBarItem(status: WebSocketStatus) {
        this.statusBarItem.tooltip = status.msg;
        this.statusBarItem.color = new ThemeColor(status.connected ? "leetcode.green" : "leetcode.red");
        this.statusBarItem.command = status.connected ? undefined : "leetcode.open.browser";
    }

    /**
     * 打开浏览器连接页面
     */
    openBrowser() {
        // 启动默认浏览器
        exec("start https://leetcode.cn/playground/?leet-code-ultimate");
    }
}

export const webSocketService = new WebSocketService();